﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DbFrame.SqlContext
{
    //
    using System.Linq.Expressions;
    using DbFrame.Ado;
    using DbFrame.Class;

    public class AddContext : Abstract.AbstractAdd
    {

        private string _ConnectionString { get; set; }
        private DbHelper _DbHelper = null;
        private DataBaseType _DataBaseType;
        public AddContext(string ConnectionString, DataBaseType DataBaseType)
        {
            this._ConnectionString = ConnectionString;
            this._DbHelper = new DbHelper(ConnectionString, DataBaseType);
            this._DataBaseType = DataBaseType;
        }

        public override object Add<T>(T Model)
        {
            var body = ReflexHelper.MemberInit<T>(Model);
            return this.Execute<T>(ref body, Model);
        }

        public override object Add<T>(Expression<Func<T>> Func)
        {
            var body = (Func.Body as MemberInitExpression);
            return this.Execute<T>(ref body, ReflexHelper.CreateInstance<T>());
        }

        public override object Add<T>(T Model, List<SQL> li)
        {
            var body = ReflexHelper.MemberInit<T>(Model);
            return this.Execute<T>(ref body, Model, li);
        }

        public override object Add<T>(Expression<Func<T>> Func, List<SQL> li)
        {
            var body = (Func.Body as MemberInitExpression);
            return this.Execute<T>(ref body, ReflexHelper.CreateInstance<T>(), li);
        }

        private string Execute<T>(ref MemberInitExpression body, T Model, List<SQL> li = null) where T : BaseEntity, new()
        {
            var _modelKey = Model.GetKey();
            var Id = this.CreatePrimaryKey<T>(ref body, _modelKey.FieldName, _modelKey.FieldType, _modelKey.IsIdentity).GetString();
            var Sql = this.Analysis<T>(body, Model);

            if (li == null && _modelKey.FieldType == typeof(int?) && _modelKey.IsIdentity && Id.StartsWith("ID#"))
            {
                Sql.Sql = Sql.Sql.Replace("/*GetId()*/", Id);
                Sql.Sql_Parameter = Sql.Sql_Parameter.Replace("/*GetId()*/", Id);
                Id = _DbHelper.ExecuteScalar<int?>(Sql.Sql_Parameter, Sql.Parameter).GetString();
                return Id;
            }

            Sql.Sql = Sql.Sql.Replace("/*GetId()*/", "");
            Sql.Sql_Parameter = Sql.Sql_Parameter.Replace("/*GetId()*/", "");

            if (li == null)
            {
                if (!_DbHelper.Commit(new List<SQL>() { Sql })) Id = string.Empty;
                return Id;
            }

            li.Add(Sql);

            return Id;
        }

        private SQL Analysis<T>(MemberInitExpression Body, T Model) where T : BaseEntity, new()
        {
            Code = new StringBuilder();

            string TabName = Model.GetTabelName();
            var _modelKey = Model.GetKey();
            var SqlPar = new Dictionary<string, object>();

            Code.Append("INSERT INTO " + TabName + " ");

            var col = new List<string>();
            var val = new List<string>();

            foreach (MemberAssignment item in Body.Bindings)
            {
                //检测有无忽略字段
                if (Model.GetIgnore().Find(w => w == item.Member.Name) != null) continue;
                var value = this.Eval(item.Expression);
                var name = item.Member.Name;
                var len = SqlPar.Count;

                //检查 特殊情况
                if (this._DataBaseType == DataBaseType.Oracle && name == _modelKey.FieldName && _modelKey.FieldType == typeof(int?) && _modelKey.IsIdentity)
                {
                    value = "MY_SEQ.NEXTVAL";
                }

                col.Add(name);
                val.Add("@" + name + "_" + len);

                SqlPar.Add(name + "_" + len, value);
            }

            Code.Append(string.Format("({0}) VALUES ({1});/*GetId()*/", string.Join(",", col), string.Join(",", val)));

            return new SQL(Code.ToString(), SqlPar);
        }

        /// <summary>
        /// 创建主键
        /// </summary>
        /// <returns></returns>
        private object CreatePrimaryKey<T>(ref MemberInitExpression body, string FiledName, Type type, bool IsIdentity) where T : BaseEntity, new()
        {
            object id;

            if (type == typeof(Guid?))
            {
                var list = new List<MemberBinding>();
                var Model = ReflexHelper.CreateInstance<T>();
                //检测 用户是否自己设置了主键
                var member = (body.Bindings.Where(item => item.Member.Name == FiledName).FirstOrDefault() as MemberAssignment);
                if (member == null)
                {
                    id = Guid.NewGuid();
                    var memberinfo = Model.GetType().GetProperty(FiledName);
                    list.Add(Expression.Bind(memberinfo, Expression.Constant(id, typeof(Guid?))));
                }
                else
                {
                    if (this.Eval(member.Expression) == null)
                        id = Guid.NewGuid();
                    else
                        id = this.Eval(member.Expression);
                }

                foreach (MemberAssignment item in body.Bindings)
                {
                    if (item.Member.Name == FiledName)
                        list.Add(Expression.Bind(item.Member, Expression.Constant(id, item.Expression.Type)));
                    else
                        list.Add(Expression.Bind(item.Member, Expression.Constant(this.Eval(item.Expression), item.Expression.Type)));
                }

                body = Expression.MemberInit(Expression.New(typeof(T)), list);
                return id;
            }
            else if (type == typeof(int?) && IsIdentity)
            {
                return this.GetLastInsertId();
            }
            else
            {
                return this.Eval(((body.Bindings.Where(item => item.Member.Name == FiledName).FirstOrDefault()) as MemberAssignment).Expression);
            }
        }

        /// <summary>
        /// 获取最后一次 插入的 ID
        /// </summary>
        /// <returns></returns>
        private string GetLastInsertId()
        {
            var str = "ID#";
            if (_DataBaseType == DataBaseType.SqlServer)
            {
                str = "SELECT LAST_INSERT_ID();";
            }
            else if (_DataBaseType == DataBaseType.MySql)
            {
                str = "SELECT SCOPE_IDENTITY();";
            }
            else if (_DataBaseType == DataBaseType.Oracle)
            {
                //INSERT INTO USERLIST(ID,USERNAME,USERPWD) VALUES(MY_SEQ.NEXTVAL,'AA1','AA1');
                //select MY_SEQ.currval from dual 
                str = "SELECT MY_SEQ.currval FROM dual;";
            }
            else
            {
                throw new Exception("数据库暂不受支持！");
            }
            return str;
        }

    }
}
